package samples.objectivefunctions;

import its.model.RID;
import its.model.environment.crossroad.Program;
import its.opt.program.Evaluator;
import its.opt.utils.OptimizationEvaluatorUtils;
import its.util.RandomFactory;

import java.util.Map;
import java.util.Random;
import java.util.logging.Logger;

import engine.ObjectiveFunction;
import engine.individuals.TrafficNetIndividual;

public class ProgramTrafficAmount<T  extends TrafficNetIndividual<?>> implements ObjectiveFunction<T> {

	private static final Logger LOGGER = Logger
			.getLogger(ProgramTrafficAmount.class.getName());
	
	private int goodIndividuals = 0;
	private Evaluator evaluator;
	
	private Random random;
	
	public ProgramTrafficAmount(Evaluator evaluator) {
		this.evaluator = evaluator;
	}

	@Override
	public double compute(T individual) {

		if (!individual.isFeasibleSolution())
		{
			StringBuilder builder = new StringBuilder();
			builder.append("Bad individual: ");
			builder.append(individual);
			LOGGER.warning(builder.toString());
			return Double.NEGATIVE_INFINITY;
		}
		++goodIndividuals;
		
		changeRandomGenerator();
		Program[] programArray = individual.getPrograms();
		Map<RID, Program> programs = 
			OptimizationEvaluatorUtils
				.packProgramsToMap(programArray);
		double result = evaluator.eval(programs);
		revertRandomGenerator();
		LOGGER.fine(result + " " + individual);
		return -result;
	}

	private void revertRandomGenerator() {
		RandomFactory.setRandom(random);
	}

	private void changeRandomGenerator() {
		backupRandomGenerator();
		setNewRandomGenerator();
	}

	private void backupRandomGenerator() {
		random = RandomFactory.getRandom();
	}
	
	private void setNewRandomGenerator() {
		RandomFactory.setRandom(new Random(123456L));
	}

	/**
	 * @return the goodIndividuals
	 */
	public int getGoodIndividuals() {
		return goodIndividuals;
	}

}
